home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / lookup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-20  |  31.2 KB  |  1,326 lines

  1. /* @(#)src/lookup.c    1.14 9/20/92 18:45:55 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  *
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * lookup.c:
  13.  *    search for values corresponding to keys using a specified
  14.  *    access method.
  15.  *
  16.  *    external functions:  open_database, close_database, lookup_database
  17.  *
  18.  * NeXT NetInfo aliases support added by Dan Danz <dan@az.stratus.com>
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <signal.h>
  26. #include <errno.h>
  27. #include "defs.h"
  28. #ifdef    UNIX_BSD
  29. # include <sys/file.h>
  30. #endif
  31. #ifdef    HAVE_YP
  32. # include "jump.h"
  33. # include <rpcsvc/ypclnt.h>
  34. #endif
  35. #include "smail.h"
  36. #include "lookup.h"
  37. #include "dys.h"
  38. #include "exitcodes.h"
  39. #ifdef HAVE_NIALIAS
  40. # include <aliasdb.h>
  41. #endif
  42. #ifndef DEPEND
  43. # include "extern.h"
  44. # include "debug.h"
  45. #endif
  46.  
  47. #if defined(HAVE_DBM) && !defined(HAVE_NDBM)
  48. # undef NULL
  49. # include <dbm.h>
  50. # undef NULL
  51. # define NULL 0
  52. #else
  53. # ifdef HAVE_NDBM
  54. #  include <ndbm.h>
  55. # else
  56. #  include "sdbm.h"
  57. #  define HAVE_NDBM
  58. # endif
  59. #endif
  60.  
  61. /* functions local to this file */
  62. static int bsearch_open();
  63. static void bsearch_close();
  64. static int bsearch_lookup();
  65.  
  66. static int lsearch_open();
  67. static void lsearch_close();
  68. static int lsearch_lookup();
  69.  
  70. static int dbmbase_open();
  71. static void dbmbase_close();
  72. static int dbmbase_lookup();
  73.  
  74. #ifdef    HAVE_YP
  75. static int yp_open();
  76. static void yp_close();
  77. static int yp_lookup();
  78.  
  79. static int aliasyp_open();
  80. static void aliasyp_close();
  81. static int aliasyp_lookup();
  82. #endif
  83.  
  84. #ifdef HAVE_NIALIAS
  85. static int aliasni_open();
  86. static void aliasni_close();
  87. static int aliasni_lookup();
  88. #endif
  89.  
  90.  
  91. /*
  92.  * the following structure defines the available access methods.
  93.  * Methods are identified by name when open_database is called.
  94.  */
  95. static struct proto {
  96.     char *proto;            /* name of the access method */
  97.     int (*open)();            /* open database function */
  98.     void (*close)();            /* close database function */
  99.     int (*lookup)();            /* lookup in database function */
  100. } protos[] = {
  101.     { "bsearch",            /* binary search */
  102.       bsearch_open, bsearch_close, bsearch_lookup },
  103.     { "lsearch",
  104.       lsearch_open, lsearch_close, lsearch_lookup },
  105.     { "dbm",                /* DBM database search */
  106.       dbmbase_open, dbmbase_close, dbmbase_lookup },
  107. #ifdef    HAVE_YP
  108.     { "yp",                /* YP remote database search */
  109.       yp_open, yp_close, yp_lookup },
  110.     { "aliasyp",            /* mail.aliases-style YP database */
  111.       aliasyp_open, aliasyp_close, aliasyp_lookup },
  112. #endif
  113. #ifdef HAVE_NIALIAS
  114.     { "nialias",            /* NetInfo remote alias search */
  115.       aliasni_open, aliasni_close, aliasni_lookup },
  116. #endif /* HAVE_NIALIAS */
  117. };
  118.  
  119. /* point to end of protos table */
  120. struct proto *end_protos = protos + sizeof(protos)/sizeof(protos[0]);
  121.  
  122. /* generic form of structure returned by database open calls */
  123. struct generic_db {
  124.     struct proto *proto;        /* access method */
  125. };
  126.  
  127. /*
  128.  * open_database - open a database of the specified type
  129.  *
  130.  * given a database name and an access method return a pointer to opaque
  131.  * data that can be used to access that database.
  132.  *
  133.  * return:
  134.  *   FILE_SUCCEED
  135.  *        if the open was successful.  The database info will
  136.  *        be stored in *db.
  137.  *   FILE_AGAIN    if the open failed but may succeed at a later time
  138.  *        (e.g., a remote host is down right now).  An error will
  139.  *        be stored in *error.
  140.  *   FILE_FAIL    if an unrecoverable failure occured.  An error will be
  141.  *        stored in *error.
  142.  *   FILE_NOMATCH
  143.  *        if the database does not appear to exist.
  144.  */
  145. int
  146. open_database(name, proto, retries, interval, statp, db, error)
  147.     char *name;                /* name of database */
  148.     char *proto;            /* access method name */
  149.     int retries;            /* retry count */
  150.     int interval;            /* retry interval */
  151.     struct stat *statp;            /* return a stat buffer */
  152.     char **db;                /* store open database info here */
  153.     char **error;            /* store error message here */
  154. {
  155.     register struct proto *pp;
  156.  
  157.     for (pp = protos; pp < end_protos; pp++) {
  158.     if (EQ(proto, pp->proto)) {
  159.         /* found the requested access method */
  160.         return (*pp->open)(name, pp, retries, interval, statp, db, error);
  161.     }
  162.     }
  163.  
  164.     /* access method was not found */
  165.     *error = "unknown proto";
  166.     return FILE_FAIL;
  167. }
  168.  
  169. /*
  170.  * close_database - close an open database and free its resources
  171.  */
  172. void
  173. close_database(priv)
  174.     char *priv;                /* database's private data */
  175. {
  176.     register struct generic_db *gp = (struct generic_db *)priv;
  177.  
  178.     (*gp->proto->close)(gp);
  179. }
  180.  
  181. /*
  182.  * lookup_database - find a value corresponding to a key
  183.  *
  184.  * given an open database, perform a lookup operation to find a match for
  185.  * a given key.
  186.  *
  187.  * Return:
  188.  *   DB_SUCCEED if the lookup was successful.  The matched value will
  189.  *         be stored in *value.
  190.  *   DB_NOMATCH    if the lookup operation did not find a match for the key.
  191.  *   DB_AGAIN    if the lookup operation failed but may succeed at a later
  192.  *        time (e.g., a remote host is down right now).  An error
  193.  *        will be stored in *error.
  194.  *   DB_FAIL    if an unrecoverable failure occured.  An error will be
  195.  *        stored in *error.
  196.  *   FILE_AGAIN    if the lookup operation failed because of an error accessing
  197.  *        the file.  The file should be considered unreachable until
  198.  *        some later time.
  199.  *   FILE_FAIL    if the lookup operation failed because of a permanent error
  200.  *        accessing the file.  Retrying at a later time is not assumed
  201.  *        to be possible.
  202.  */
  203. int
  204. lookup_database(db, key, value, error)
  205.     char *db;                /* open database */
  206.     char *key;                /* search key */
  207.     char **value;            /* store value here */
  208.     char **error;            /* store error message here */
  209. {
  210.     register struct generic_db *gdb = (struct generic_db *)db;
  211.  
  212.     return (*gdb->proto->lookup)(gdb, key, value, error);
  213. }
  214.  
  215. /*
  216.  * bsearch access method:
  217.  *
  218.  *    access a file containing sorted lines of data.  keys
  219.  *    are at the start of each line followed by a colon and/or
  220.  *    white space.
  221.  */
  222.  
  223. /* private data: */
  224. struct bsearch_db {
  225.     struct proto *proto;        /* access method table entry */
  226.     char *name;                /* name of file */
  227.     FILE *f;                /* open file */
  228.     long size;                /* size of file */
  229. };
  230.  
  231. /* bsearch_open - open a sorted file */
  232. static int
  233. bsearch_open(name, proto, retries, interval, statp, db, error)
  234.     char *name;                /* name of file */
  235.     struct proto *proto;        /* access method */
  236.     int retries;            /* retry count */
  237.     int interval;            /* retry interval */
  238.     struct stat *statp;            /* save stat results here */
  239.     char **db;                /* store open database info here */
  240.     char **error;            /* store error message here */
  241. {
  242.     register struct bsearch_db *priv;
  243.     register FILE *f;
  244.  
  245.     name = make_lib_fn(name);
  246.     if (name == NULL) {
  247.     *error = "No directory for file";
  248.     return FILE_FAIL;
  249.     }
  250.     f = fopen(name, "r");
  251.     if (f == NULL) {
  252.     int left = retries;
  253.  
  254.     while (left-- > 0) {
  255.         (void) sleep(interval);
  256.         if (f = fopen(name, "r")) break;
  257.     }
  258.     if (f == NULL) {
  259.         if (errno == ENOENT) {
  260.         return FILE_NOMATCH;
  261.         }
  262.         *error = strerrno();
  263.         return FILE_FAIL;
  264.     }
  265.     }
  266.  
  267. #ifdef lock_fd_rd_wait
  268.     if (lock_fd_rd_wait(fileno(f)) < 0) {
  269.     *error = "database is locked, try again later";
  270.     return FILE_AGAIN;
  271.     }
  272. #endif
  273.  
  274.     /* seek to the end of the file */
  275.     (void) fseek(f, 0L, 2);
  276.  
  277.     /* build the private data */
  278.     priv = (struct bsearch_db *)xmalloc(sizeof(*priv));
  279.     priv->proto = proto;
  280.     priv->name = name;
  281.     priv->f = f;
  282.     priv->size = ftell(f);        /* remember the fseek() */
  283.     if (statp) {
  284.     (void) fstat(fileno(f), statp);
  285.     }
  286.  
  287.     *db = (char *)priv;
  288.     return FILE_SUCCEED;
  289. }
  290.  
  291. /* bsearch_close - close the file */
  292. static void
  293. bsearch_close(db)
  294.     struct bsearch_db *db;
  295. {
  296.     (void) fclose(db->f);
  297.     xfree((char *)db);
  298. }
  299.  
  300. /*
  301.  * bsearch_lookup - look up key in ascii sorted key/data line database.
  302.  *
  303.  * This routine taken from smail version 2.3, though it has been
  304.  * modified to work with the new version and has also been
  305.  * generalized from the original routine getpath().
  306.  */
  307. /*ARGSUSED*/
  308. static int
  309. bsearch_lookup(db, key, value, error)
  310.     register struct bsearch_db *db;
  311.     char *key;
  312.     char **value;
  313.     char **error;
  314. {
  315.     long middle, hi, lo;
  316.     int c;
  317.     int flag;
  318.     static struct str str;        /* string in which to store data */
  319.     static int str_inited = FALSE;    /* TRUE if str has been STR_INIT'd */
  320.     int i;                /* temp */
  321.  
  322.     DEBUG1(DBG_DRIVER_HI, "bsearch_lookup: looking for <%s>\n", key);
  323.  
  324.     if (!str_inited) {
  325.     /*
  326.      * note, the string is reused in each call to bsearch.
  327.      */
  328.     str_inited = TRUE;
  329.     STR_INIT(&str);
  330.     }
  331.  
  332.     lo = 0;
  333.     hi = db->size;
  334.  
  335.     /*
  336.      * "Binary search routines are never written right the first time around."
  337.      * - Robert G. Sheldon.
  338.      * << above comment retained 'cause I thought it was cute -- tron >>
  339.      * << it is also true -- tron >>
  340.      */
  341.     for( ;; ) {
  342.     int cnt;
  343.  
  344.     middle = (hi + lo + 1)/2;
  345.     (void) fseek(db->f, middle, 0); /* find midpoint */
  346.     if (middle != 0) {        /* to beginning of next line */
  347.         while((c = getc(db->f)) != EOF && c != '\n') ;
  348.         if (c == EOF && ferror(db->f)) {
  349.         *error = strerrno();
  350.         clearerr(db->f);
  351.         return FILE_FAIL;
  352.         }
  353.     }
  354.     str.i = 0;
  355.     cnt = 0;
  356.     while ((c = getc(db->f)) != EOF && !isspace(c) && c != ':') {
  357.         STR_NEXT(&str, c);
  358.         cnt++;
  359.     }
  360.     if (c == EOF && ferror(db->f)) {
  361.         *error = strerrno();
  362.         clearerr(db->f);
  363.         return FILE_FAIL;
  364.     }
  365.     STR_NEXT(&str, '\0');
  366.     flag = strcmpic(str.p, key);
  367.     if (flag == 0)
  368.         break;
  369.     if ( lo>=middle ) {        /* failure? */
  370.         return DB_NOMATCH;
  371.     }
  372.     if ( c != EOF && flag < 0 ) {    /* close window */
  373.         lo = middle;
  374.     } else {
  375.         hi = middle - 1;
  376.     }
  377.     }
  378.  
  379.     /*
  380.      * Now just copy the result.
  381.      */
  382.     i = -1;                /* index to last non-space */
  383.     str.i = 0;                /* clear out the region */
  384.     while(((c  = getc(db->f)) != EOF) && (c != '\n')) {
  385.     if (!isspace(c)) {
  386.         if (c == '#') {
  387.         /* comment puts an end to the entry */
  388.         break;
  389.         }
  390.         i = str.i;
  391.     }
  392.     STR_NEXT(&str, c);
  393.     }
  394.     if (c == EOF && ferror(db->f)) {
  395.     *error = strerrno();
  396.     clearerr(db->f);
  397.     return FILE_FAIL;
  398.     }
  399.     str.i = i + 1;            /* backup to last interesting char */
  400.     /* backup to last non-space character */
  401.     STR_NEXT(&str, '\0');
  402.  
  403.     DEBUG2(DBG_DRIVER_HI, "bsearch_lookup: found <%s> for <%s>\n", str.p, key);
  404.     *value = str.p;
  405.     return DB_SUCCEED;
  406. }
  407.  
  408. /*
  409.  * lsearch access method:
  410.  *
  411.  *    access a file containing lines of data, in the format expected
  412.  *    by read_entry() in parse.c.  Keys are at the start of each line
  413.  *    followed by a colon and/or white space.
  414.  */
  415.  
  416. /* private data: */
  417. struct lsearch_db {
  418.     struct proto *proto;        /* access method table entry */
  419.     char *name;                /* name of file */
  420.     FILE *f;                /* open file */
  421. };
  422.  
  423. /* lsearch_open - open a file */
  424. static int
  425. lsearch_open(name, proto, retries, interval, statp, db, error)
  426.     char *name;                /* name of file */
  427.     struct proto *proto;        /* access method */
  428.     int retries;            /* retry count */
  429.     int interval;            /* retry interval */
  430.     struct stat *statp;            /* save stat results here */
  431.     char **db;                /* store open database info here */
  432.     char **error;            /* store error message here */
  433. {
  434.     register struct lsearch_db *priv;
  435.     register FILE *f;
  436.  
  437.     name = make_lib_fn(name);
  438.     if (name == NULL) {
  439.     *error = "No directory for file";
  440.     return FILE_FAIL;
  441.     }
  442.     f = fopen(name, "r");
  443.     if (f == NULL) {
  444.     int left = retries;
  445.  
  446.     while (left-- > 0) {
  447.         (void) sleep(interval);
  448.         if (f = fopen(name, "r")) break;
  449.     }
  450.     if (f == NULL) {
  451.         if (errno == ENOENT) {
  452.         return FILE_NOMATCH;
  453.         }
  454.         *error = strerrno();
  455.         return FILE_FAIL;
  456.     }
  457.     }
  458.  
  459. #ifdef lock_fd_rd_wait
  460.     if (lock_fd_rd_wait(fileno(f)) < 0) {
  461.     *error = "database is locked, try again later";
  462.     return FILE_AGAIN;
  463.     }
  464. #endif
  465.  
  466.     /* build the private data */
  467.     priv = (struct lsearch_db *)xmalloc(sizeof(*priv));
  468.     priv->proto = proto;
  469.     priv->name = name;
  470.     priv->f = f;
  471.     if (statp) {
  472.     (void) fstat(fileno(f), statp);
  473.     }
  474.  
  475.     *db = (char *)priv;
  476.     return FILE_SUCCEED;
  477. }
  478.  
  479. /* lsearch_close - close the file */
  480. static void
  481. lsearch_close(db)
  482.     struct lsearch_db *db;
  483. {
  484.     (void) fclose(db->f);
  485.     xfree((char *)db);
  486. }
  487.  
  488. /*
  489.  * lsearch_lookup - look up key with a linear search
  490.  */
  491. /*ARGSUSED*/
  492. static int
  493. lsearch_lookup(db, key, value, error)
  494.     register struct lsearch_db *db;
  495.     char *key;
  496.     char **value;
  497.     char **error;
  498. {
  499.     int len = strlen(key);        /* length of comparison */
  500.     register char *entry;        /* entry from read_entry() */
  501.     register char *p;            /* temp */
  502.  
  503.     DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: looking for <%s>\n", key);
  504.  
  505.     /* always start from the beginning of the file */
  506.     (void) fseek(db->f, 0L, 0);
  507.  
  508.     while (entry = read_entry(db->f)) {
  509.     if (strncmpic(entry, key, len) == 0 &&
  510.         (entry[len] == ':' || isspace(entry[len])))
  511.     {
  512.         char *ret;            /* value to be returned */
  513.  
  514.         /* found a matching entry in the file, find the data */
  515.         entry += len;
  516.         /*
  517.          * skip <whitespace>:<whitespace>
  518.          */
  519.         while (isspace(*entry)) entry++;
  520.         if (*entry == ':') {
  521.         entry++;
  522.         while (isspace(*entry)) entry++;
  523.         }
  524.  
  525.         /*
  526.          * skip comments
  527.          */
  528.         while (*entry == '#') {
  529.         while (*entry && *entry != '\n') entry++;
  530.         while (isspace(*entry)) entry++;
  531.         }
  532.         ret = entry;        /* return from this point on */
  533.  
  534.         /* though do some more processing to the remainder */
  535.         p = entry - 1;
  536.         /* find the last character which is not white-space or comment */
  537.         while (*entry) {
  538.         if (!isspace(*entry)) {
  539.             if (*entry == '#') {
  540.             while (*entry && *entry != '\n') entry++;
  541.             continue;
  542.             }
  543.             p = entry;
  544.         }
  545.         entry++;
  546.         }
  547.         /* throw away after the last interesting character */
  548.         p[1] = '\0';
  549.  
  550.         DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: return <%s>\n", ret);
  551.  
  552.         *value = ret;
  553.         return DB_SUCCEED;
  554.     }
  555.     }
  556.     if (ferror(db->f)) {
  557.     *error = strerrno();
  558.     return FILE_FAIL;
  559.     }
  560.     DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: did not find <%s>\n", key);
  561.     return DB_NOMATCH;
  562. }
  563.  
  564. /*
  565.  * dbmbase access method:
  566.  *
  567.  *    access a database stored as a DBM database.  Note that the
  568.  *    DBM semantics only allow for one DBM file in the life of
  569.  *    a process.  As a result, these files should never be closed
  570.  *    and only one reference to a DBM-type database can exist in
  571.  *    the application.
  572.  *
  573.  *    BUGS:  extensive use of #ifdef within functions is ugly.
  574.  */
  575.  
  576. /*
  577.  * form for private data:
  578.  */
  579. struct dbmbase_db {
  580.     struct proto *proto;        /* access method table entry */
  581.     char *name;                /* name of database */
  582. #ifdef HAVE_NDBM
  583.     DBM *db;                /* open database */
  584. #endif
  585. };
  586.  
  587. #ifndef HAVE_NDBM
  588. static struct dbmbase_db *opendb = NULL;
  589. #endif
  590.  
  591. /* dbmbase_open - open a DBM database */
  592. static int
  593. dbmbase_open(name, proto, retries, interval, statp, db, error)
  594.     char *name;                /* name of database */
  595.     struct proto *proto;        /* access method */
  596.     int retries;            /* retry count */
  597.     int interval;            /* retry interval */
  598.     struct stat *statp;            /* return a stat structure */
  599.     char **db;                /* store open database info here */
  600.     char **error;            /* store error message here */
  601. {
  602.     char *pag_file;            /* name of .pag file */
  603.     register struct dbmbase_db *priv;
  604.  
  605.     name = make_lib_fn(name);
  606.     if (name == NULL) {
  607.     *error = "No directory for file";
  608.     return FILE_FAIL;
  609.     }
  610.     priv = (struct dbmbase_db *)xmalloc(sizeof(*priv));
  611.  
  612. #ifndef HAVE_NDBM
  613.     if (opendb != NULL) {
  614.     dbmclose();
  615.     opendb = NULL;
  616.     }
  617. #endif
  618.  
  619. #ifdef HAVE_NDBM
  620.     if ((priv->db = dbm_open(name, 0, 0)) == NULL)
  621. #else
  622.     if (dbminit(name) < 0)
  623. #endif
  624.     {
  625.     int succeed = FAIL;
  626.     int left = retries;
  627.  
  628.     if (left < 1) {
  629.         /* DBM databases cannot be moved atomicly, so require
  630.          * at least two retries */
  631.         left = 2;
  632.     }
  633.     if (interval < 2) {
  634.         /* require a somewhat reasonable interval as well */
  635.         interval = 2;
  636.     }
  637.  
  638.     while (left-- > 0) {
  639.         (void) sleep(interval);
  640. #ifdef HAVE_NDBM
  641.         if ((priv->db = dbm_open(name, 0, 0)) != NULL)
  642. #else
  643.         if (dbminit(name) == 0)
  644. #endif
  645.         {
  646.         succeed = SUCCEED;
  647.         break;
  648.         }
  649.         if (errno != ENOENT) {
  650.         break;
  651.         }
  652.     }
  653.     if (succeed != DB_SUCCEED) {
  654.         if (errno == ENOENT)
  655.         return FILE_NOMATCH;
  656.         *error = strerrno();
  657.         return FILE_FAIL;
  658.     }
  659.     }
  660.  
  661. #ifndef HAVE_NDBM
  662.     opendb = priv;
  663. #endif
  664.  
  665.     /* if required, get a stat structure from the .pag file */
  666.     if (statp) {
  667.     pag_file = xmalloc(strlen(name) + sizeof(".pag"));
  668.     (void) sprintf(pag_file, "%s.pag", name);
  669.     (void) stat(pag_file, statp);
  670.     xfree(pag_file);
  671.     }
  672.     priv->proto = proto;
  673.     priv->name = name;
  674.     *db = (char *)priv;
  675. #if defined(HAVE_NDBM) && defined(lock_fd_rd_wait)
  676.     if (lock_fd_rd_wait(dbm_pagfno(priv->db)) < 0) {
  677.     *error = "database is locked, try again later";
  678.     return FILE_AGAIN;
  679.     }
  680. #endif /* HAVE_NDBM && lock_fd_rd_wait */
  681.     return FILE_SUCCEED;
  682. }
  683.  
  684. /* dbmbase_close - close the database */
  685. static void
  686. dbmbase_close(db)
  687.     struct dbmbase_db *db;
  688. {
  689. #ifdef HAVE_NDBM
  690.     (void) dbm_close(db->db);
  691. #else
  692.     if (opendb == db) {
  693.     dbmclose();
  694.     opendb = NULL;
  695.     }
  696. #endif
  697.     xfree((char *)db);
  698.     return;
  699. }
  700.  
  701. /* dbmbase_lookup - call on the DBM routines to find that data */
  702. static int
  703. dbmbase_lookup(db, key, value, error)
  704.     register struct dbmbase_db *db;
  705.     char *key;
  706.     char **value;
  707.     char **error;
  708. {
  709.     datum the_key;
  710.     datum the_value;
  711.     static int temp_size;        /* size of temp_key area */
  712.     static char *temp_data = NULL;    /* growable temp area */
  713.     int len;                /* length of key */
  714.     register char *p;
  715.  
  716. #ifndef HAVE_NDBM
  717.     if (opendb != db) {
  718.     if (opendb) {
  719.         dbmclose();
  720.         opendb = NULL;
  721.     }
  722.     if (dbminit(db->name) < 0)
  723.         return FAIL;
  724.     }
  725. #endif
  726.  
  727.     /*
  728.      * convert the key to lower case, as fetch() is case-sensitive
  729.      * for efficiency, keep around the malloc'd region used to store
  730.      * the down-cased key.
  731.      */
  732.     len = strlen(key) + 1;
  733.     if (temp_data == NULL) {
  734.     temp_size = len;
  735.     temp_data = xmalloc(temp_size);
  736.     } else if (temp_size < len) {
  737.     temp_size = len;
  738.     temp_data = xrealloc(temp_data, temp_size);
  739.     }
  740.     for (p = temp_data; *key; p++, key++) {
  741.     *p = lowercase(*key);
  742.     }
  743.     *p = '\0';
  744.  
  745.     the_key.dptr = temp_data;
  746.     the_key.dsize = len;
  747. #ifdef HAVE_NDBM
  748.     the_value = dbm_fetch(db->db, the_key);
  749.     if (dbm_error(db->db)) {
  750.     *error = xprintf("Error in fetching %s", the_key);
  751.     return FILE_FAIL;
  752.     }
  753. #else
  754.     the_value = fetch(the_key);
  755. #endif
  756.  
  757.     if (the_value.dptr) {
  758.     if (temp_size < the_value.dsize + 1) {
  759.         temp_size = the_value.dsize + 1;
  760.         temp_data = xrealloc(temp_data, temp_size);
  761.     }
  762.     (void) strcpy(temp_data, the_value.dptr);
  763.     *value = temp_data;
  764.     return DB_SUCCEED;
  765.     }
  766.     return DB_NOMATCH;
  767. }
  768.  
  769. #ifdef    HAVE_YP
  770. /*
  771.  * The YP database routines takes names of the form:
  772.  *
  773.  *    domain:database_name
  774.  * or    database_name
  775.  *
  776.  * in the former case, the `domain' specified is the YP domain to use
  777.  * for yp_match operations.  In the second case, the default YP domain
  778.  * is used.
  779.  *
  780.  * There are two forms for the lookup: regular yp and aliasyp.  The
  781.  * second form is used for accessing the standard Sun mail.aliases map
  782.  * format, which does not fit the form of other YP maps.  The
  783.  * difference is that a nul-byte is counted in the length of a key for
  784.  * mail.aliases, while it is not counted for other maps.
  785.  */
  786.  
  787. /*
  788.  * form for private data:
  789.  */
  790. struct yp_db {
  791.     struct proto *proto;        /* access method table entry */
  792.     char *map;                /* name of database */
  793.     char *domain;            /* yp domain */
  794. };
  795.  
  796. static char *default_yp_domain = NULL;    /* from yp_get_default_domain(3N) */
  797. static int common_yp_lookup();
  798.  
  799. #ifdef notyet
  800. static JUMP_ENVBUF alarm_jmp;        /* jump here on SIGALRM */
  801.  
  802. static void yp_sigalrm();        /* catch SIGALRM for YP timeouts */
  803.  
  804. #define YP_TIMEOUT    30        /* 30 second timeout for YP */
  805. #endif
  806.  
  807. /*
  808.  * yp_open, aliasyp_open - create a yp_private structure for a database
  809.  *
  810.  * yp_order(3N) is called to verify that the database is accessible.
  811.  */
  812. static int
  813. aliasyp_open(name, proto, retries, interval, statp, db, error)
  814.     char *name;                /* name of database */
  815.     struct proto *proto;        /* access method */
  816.     int retries;            /* retry count */
  817.     int interval;            /* retry interval */
  818.     struct stat *statp;            /* return a stat structure */
  819.     char **db;                /* store open database info here */
  820.     char **error;            /* store error message here */
  821. {
  822.     return yp_open(name, proto, retries, interval, statp, db, error);
  823. }
  824.  
  825. /*ARGSUSED*/
  826. static int
  827. yp_open(name, proto, retries, interval, statp, db, error)
  828.     char *name;                /* name of database */
  829.     struct proto *proto;        /* access method */
  830.     int retries;            /* retry count */
  831.     int interval;            /* retry interval */
  832.     struct stat *statp;            /* return a stat structure */
  833.     char **db;                /* store open database info here */
  834.     char **error;            /* store error message here */
  835. {
  836.     register struct yp_db *priv;
  837.     register char *p;
  838.     int err;                /* error from yp functions */
  839.     int order;                /* output from yp_order */
  840.     char *domain;
  841. #ifdef notyet
  842.     VOLATILE int save_time;        /* saved value from alarm() */
  843.     VOLATILE JUMPSIG save_sigalrm;    /* previous SIGALRM handler */
  844. #endif
  845.  
  846.     priv = (struct yp_db *)xmalloc(sizeof(*priv));
  847.  
  848.     /* is a YP domain specified? */
  849.     p = index(name, ':');
  850.     if (p == NULL) {
  851.     /* no, use the default YP domain */
  852.     priv->domain = NULL;
  853.     priv->map = name;
  854.     } else {
  855.     /* yes, make a copy and use it */
  856.     priv->domain = xmalloc(p - name + 1);
  857.     (void) memcpy(priv->domain, name, p - name);
  858.     priv->domain[p - name] = '\0';
  859.     priv->map = p + 1;
  860.     }
  861.  
  862.     /* if stat required, just zero it out, there is nothing to put there */
  863.     if (statp) {
  864.     (void) bzero((char *)statp, sizeof(*statp));
  865.     }
  866.  
  867.     if (priv->domain) {
  868.     domain = priv->domain;
  869.     } else {
  870.     if (default_yp_domain == NULL &&
  871.         (err = yp_get_default_domain(&default_yp_domain)))
  872.     {
  873.         /* this should only fail if the domainname is not set, right? */
  874.         *error = yperr_string(err);
  875.         return FILE_FAIL;
  876.     }
  877.     domain = default_yp_domain;
  878.     }
  879.  
  880. #ifdef notyet
  881.     save_time = alarm(0);
  882.  
  883.     /* verify that we can access the database */
  884.     if (JUMP_SETJMP(alarm_jmp)) {
  885.     (void) alarm(0);
  886.     JUMP_CLEARSIG(SIGALRM, &save_sigalrm);
  887.     if (save_time) {
  888.         (void) alarm(save_time);
  889.     }
  890.  
  891.     *error = "YP timeout";
  892.     return FILE_AGAIN;
  893.     } else {
  894.  
  895.     /* arrange to timeout if the operation blocks */
  896.     JUMP_SETSIG(SIGALRM, yp_sigalrm, &save_sigalrm);
  897.     (void) alarm(YP_TIMEOUT);
  898. #endif
  899.  
  900.     /* potentially blocking operation */
  901.     err = yp_order(domain, priv->map, &order);
  902.  
  903. #ifdef notyet
  904.     /* restore previous alarm setting */
  905.     (void) alarm(0);
  906.     JUMP_CLEARSIG(SIGALRM, &save_sigalrm);
  907.     if (save_time) {
  908.         (void) alarm(save_time);
  909.     }
  910. #endif
  911.  
  912.     if (err) {
  913.         /* analyze the reason for the failure */
  914.         *error = yperr_string(err);
  915.         switch (err) {
  916.         case YPERR_RPC:        /* cases where failure is temporary */
  917.         case YPERR_YPERR:
  918.         case YPERR_RESRC:
  919.         case YPERR_PMAP:
  920.         case YPERR_YPBIND:
  921.         case YPERR_YPSERV:
  922.         return FILE_AGAIN;
  923.  
  924.         case YPERR_MAP:        /* no such map */
  925.         case YPERR_DOMAIN:        /* no such domain */
  926.         return FILE_NOMATCH;
  927.         }
  928.         return FILE_FAIL;
  929.     }
  930. #ifdef notyet
  931.     }
  932. #endif
  933.  
  934.     priv->proto = proto;
  935.     *db = (char *)priv;
  936.     return FILE_SUCCEED;
  937. }
  938.  
  939. /* yp_close, aliasyp_close - free up data allocated for to a YP database */
  940. static void
  941. aliasyp_close(db)
  942.     struct yp_db *db;
  943. {
  944.     yp_close(db);
  945. }
  946.  
  947. /*ARGSUSED*/
  948. static void
  949. yp_close(db)
  950.     struct yp_db *db;
  951. {
  952.     if (db->domain) {
  953.     xfree(db->domain);
  954.     }
  955.     xfree((char *)db);
  956.     return;
  957. }
  958.  
  959. /* yp_lookup, aliasyp_lookup - call on the YP routines to find that data */
  960. static int
  961. yp_lookup(db, key, value, error)
  962.     register struct yp_db *db;        /* open YP database */
  963.     char *key;                /* search key */
  964.     char **value;            /* return value here */
  965.     char **error;            /* return error message here */
  966. {
  967.     return common_yp_lookup(db, key, value, error, FALSE);
  968. }
  969.  
  970. static int
  971. aliasyp_lookup(db, key, value, error)
  972.     register struct yp_db *db;        /* open YP database */
  973.     char *key;                /* search key */
  974.     char **value;            /* return value here */
  975.     char **error;            /* return error message here */
  976. {
  977.     return common_yp_lookup(db, key, value, error, TRUE);
  978. }
  979.  
  980. /*ARGSUSED*/
  981. static int
  982. common_yp_lookup(db, key, value, error, aliasflag)
  983.     register struct yp_db *db;        /* open YP database */
  984.     char *key;                /* search key */
  985.     char **value;            /* return value here */
  986.     char **error;            /* return error message here */
  987.     int aliasflag;            /* TRUE for Sun mail.aliases format */
  988. {
  989.     int keylen;                /* length of key */
  990.     static char *temp_key = NULL;    /* area for lower-case conversion */
  991.     static int temp_size;        /* size of temp area */
  992.     register char *p;
  993.     char *matchval;            /* matched data */
  994.     int matchlen;            /* length of matched data */
  995.     int err;                /* yp error */
  996.     char *domain;
  997. #ifdef notyet
  998.     VOLATILE int save_time;        /* saved value from alarm() */
  999.     VOLATILE JUMPSIG save_sigalrm;    /* previous SIGALRM handler */
  1000. #endif
  1001.  
  1002.     /*
  1003.      * convert the key to lower case, as fetch() is case-sensitive
  1004.      * for efficiency, keep around the malloc'd region used to store
  1005.      * the down-cased key.
  1006.      */
  1007.     keylen = strlen(key);
  1008.     if (temp_key == NULL) {
  1009.     temp_size = keylen + 1;
  1010.     temp_key = xmalloc(temp_size);
  1011.     } else if (temp_size <= keylen) {
  1012.     temp_size = keylen + 1;
  1013.     temp_key = xrealloc(temp_key, temp_size);
  1014.     }
  1015.     for (p = temp_key; *key; p++, key++) {
  1016.     *p = lowercase(*key);
  1017.     }
  1018.     *p = '\0';
  1019.  
  1020.     if (db->domain) {
  1021.     domain = db->domain;
  1022.     } else {
  1023.     domain = default_yp_domain;
  1024.     }
  1025.  
  1026.     if (aliasflag) {
  1027.     keylen++;
  1028.     }
  1029.  
  1030. #ifdef notyet
  1031.     save_time = alarm(0);
  1032.  
  1033.     if (JUMP_SETJMP(alarm_jmp)) {
  1034.     (void) alarm(0);
  1035.     JUMP_CLEARSIG(SIGALRM, &save_sigalrm);
  1036.     if (save_time) {
  1037.         (void) alarm(save_time);
  1038.     }
  1039.  
  1040.     *error = "YP timeout";
  1041.     return FILE_AGAIN;
  1042.     } else {
  1043.  
  1044.     /* arrange to timeout if the operation blocks */
  1045.     JUMP_SETSIG(SIGALRM, yp_sigalrm, &save_sigalrm);
  1046.     (void) alarm(YP_TIMEOUT);
  1047. #endif
  1048.  
  1049.     /* potentially blocking operation */
  1050.     err = yp_match(domain, db->map, temp_key, keylen,
  1051.                &matchval, &matchlen);
  1052.  
  1053. #ifdef notyet
  1054.     /* restore previous alarm setting */
  1055.     (void) alarm(0);
  1056.     JUMP_CLEARSIG(SIGALRM, &save_sigalrm);
  1057.     if (save_time) {
  1058.         (void) alarm(save_time);
  1059.     }
  1060. #endif
  1061.  
  1062.     if (err) {
  1063.         /* analyze the reason for the failure */
  1064.         *error = yperr_string(err);
  1065.         switch (err) {
  1066.         case YPERR_RPC:        /* cases where failure is temporary */
  1067.         case YPERR_DOMAIN:
  1068.         case YPERR_YPERR:
  1069.         case YPERR_RESRC:
  1070.         case YPERR_PMAP:
  1071.         case YPERR_YPBIND:
  1072.         case YPERR_YPSERV:
  1073.         return FILE_AGAIN;
  1074.  
  1075.         case YPERR_KEY:        /* key not in database */
  1076.         return DB_NOMATCH;
  1077.         }
  1078.         return FILE_FAIL;
  1079.     }
  1080. #ifdef notyet
  1081.     }
  1082. #endif
  1083.  
  1084.     matchval[matchlen] = '\0';        /* we don't want the extra newline */
  1085.     *value = matchval;
  1086.     return DB_SUCCEED;
  1087. }
  1088.  
  1089. #ifdef notyet
  1090. static void
  1091. yp_sigalrm()
  1092. {
  1093.     JUMP_LONGJMP(alarm_jmp, 1);
  1094. }
  1095. #endif
  1096.  
  1097. #endif    /* HAVE_YP */
  1098.  
  1099. #ifdef        HAVE_NIALIAS
  1100.  
  1101. /*
  1102.  * nialias access method
  1103.  *
  1104.  *            access the netinfo alias database.  
  1105.  *
  1106.  */
  1107.  
  1108. /* private data: */
  1109. struct aliasni_db {
  1110.     struct proto *proto;
  1111.     char *expansion_area;
  1112.     int expansion_size;
  1113. };
  1114.  
  1115. /* aliasni_open - open the netinfo database */
  1116.  
  1117. static int
  1118. aliasni_open(name, proto, retries, interval, statp, db, error)
  1119.     char *name;            /* name of file */
  1120.     struct proto *proto;    /* access method */
  1121.     int retries;        /* retry count */
  1122.     int interval;        /* retry interval */
  1123.     struct stat *statp;        /* save stat results here */
  1124.     char **db;            /* store open database info here */
  1125.     char **error;        /* store error message here */
  1126. {
  1127.     register struct aliasni_db *priv;
  1128.  
  1129.     /* build the private area */
  1130.  
  1131.     alias_setent();
  1132.  
  1133.     priv = (struct aliasni_db *)xmalloc(sizeof(*priv));
  1134.     priv->proto = proto;
  1135.     priv->expansion_area = NULL;
  1136.     priv->expansion_size = 0;
  1137.  
  1138.     *db = (char *)priv;
  1139.     /* always succeeds */
  1140.     return FILE_SUCCEED;
  1141. }
  1142.  
  1143. /* aliasni_close - close the NetInfo alias database */
  1144. static void
  1145. aliasni_close(db)
  1146.     struct aliasni_db *db;
  1147. {
  1148.     alias_endent();
  1149.     xfree(db->expansion_area);
  1150.     xfree((char *)db);
  1151. }
  1152.  
  1153. /* aliasni_lookup - search for a key in the NetInfo alias database */
  1154.  
  1155. /*ARGSUSED*/
  1156. static int
  1157. aliasni_lookup(db, key, value, error)
  1158.     register struct aliasni_db *db;
  1159.     char *key;
  1160.     char **value;
  1161.     char **error;
  1162. {
  1163.     aliasent    *a;
  1164.     int i,n;
  1165.     char        *p;
  1166.  
  1167.     DEBUG1(DBG_DRIVER_HI, "aliasni_lookup: looking for <%s>\n",key);
  1168.  
  1169.     a = alias_getbyname(key);
  1170.     if ((!a) || (a->alias_members_len == 0)) {
  1171.     DEBUG1(DBG_DRIVER_HI,"aliasni_lookup: looking for <%s>\n",
  1172.            lc_fold(key));
  1173.     a = alias_getbyname(lc_fold(key));
  1174.     if ((!a) || (a->alias_members_len == 0)) {
  1175.         DEBUG1(DBG_DRIVER_HI,"aliasni_lookup: did not find <%s>\n",key);
  1176.         return DB_NOMATCH;
  1177.     }
  1178.     }
  1179.  
  1180.     /* Since this routine can return multiple member lists, then */
  1181.     /* we must expand it into a single string and then let the caller */ 
  1182.     /* parse it into the individual fields */
  1183.  
  1184.     /* calculate the size of the expansion area  */
  1185.     for (n=2,i=0;i < a->alias_members_len; i++)
  1186.     n += (strlen(a->alias_members[i])+1);
  1187.  
  1188.     if (db->expansion_size < n) {
  1189.     db->expansion_size = n;
  1190.     if (db->expansion_area)
  1191.         db->expansion_area=xrealloc(db->expansion_area, db->expansion_size);
  1192.     else
  1193.         db->expansion_area=xmalloc(db->expansion_size);
  1194.     }
  1195.  
  1196.     for (p = db->expansion_area, i=0; i < a->alias_members_len; i++)
  1197.     if (n = strlen(a->alias_members[i])) {
  1198.         *p++ = ',';                /* add a separator */
  1199.         memcpy(p,a->alias_members[i],n);    /* add these member(s) */
  1200.         p += n;
  1201.         }
  1202.     *p = '\0';                    /* terminate the string */
  1203.  
  1204.     /* if anything in the string, skip the opening separator */
  1205.     *value = (p == db->expansion_area)?p:db->expansion_area+1;
  1206.  
  1207.     DEBUG3(DBG_DRIVER_HI, "aliasni_lookup: returns %d %s  <%s>\n",
  1208.        a->alias_members_len, (a->alias_local?"local":"network"),*value);
  1209.  
  1210.     return DB_SUCCEED;
  1211. }
  1212.  
  1213. #endif /* HAVE_NIALIAS */
  1214.  
  1215. #ifdef STANDALONE
  1216.  
  1217. int debug = 0;
  1218. FILE *errfile = stderr;
  1219.  
  1220. void
  1221. main(argc, argv)
  1222.     int argc;
  1223.     char **argv;
  1224. {
  1225.     char *program = (--argc, *argv++);
  1226.     char *proto;
  1227.     char *name;
  1228.     char *db;
  1229.     char *error;
  1230.     int interval = 3;
  1231.     int retries = 0;
  1232.     int success;
  1233.  
  1234.     for (;;) {
  1235.     if (*argv && EQ(*argv, "-r")) {
  1236.         argv++;
  1237.         retries = atoi(*argv++);
  1238.         argc -= 2;
  1239.         continue;
  1240.     }
  1241.     if (*argv && EQ(*argv, "-i")) {
  1242.         argv++;
  1243.         interval = atoi(*argv++);
  1244.         argc -= 2;
  1245.         continue;
  1246.     }
  1247.     break;
  1248.     }
  1249.  
  1250.     if (argc < 3) {
  1251.     fprintf(stderr,
  1252.         "Usage: %s [-r #retries] [-i interval] proto name key ...\n",
  1253.         program);
  1254.     exit(EX_USAGE);
  1255.     }
  1256.  
  1257.     proto = *argv++;
  1258.     name = *argv++;
  1259.  
  1260.     success = open_database(name, proto, retries, interval,
  1261.                 (struct stat *)NULL, &db, &error);
  1262.     switch (success) {
  1263.     case DB_AGAIN:
  1264.     fprintf(stderr, "%s: try again later: %s\n", program, error);
  1265.     exit(EX_TEMPFAIL);
  1266.  
  1267.     case DB_FAIL:
  1268.     fprintf(stderr, "%s: open failed: %s\n", program, error);
  1269.     exit(EX_UNAVAILABLE);
  1270.     }
  1271.  
  1272.     while (*argv) {
  1273.     char *value;
  1274.  
  1275.     switch (lookup_database(db, *argv, &value, &error)) {
  1276.     case DB_AGAIN:
  1277.         fprintf(stderr, "%s: %s: try again later: %s\n",
  1278.             program, *argv, error);
  1279.         break;
  1280.  
  1281.     case DB_FAIL:
  1282.         fprintf(stderr, "%s: %s: failed: %s\n", program, *argv, error);
  1283.         break;
  1284.  
  1285.     case DB_NOMATCH:
  1286.         fprintf(stderr, "%s: %s: no match\n", program, *argv);
  1287.         break;
  1288.  
  1289.     case DB_SUCCEED:
  1290.         printf("%s --> %s", *argv, value);
  1291.         break;
  1292.     }
  1293.     argv++;
  1294.     }
  1295.  
  1296.     close_database(db);
  1297.     exit(EX_OK);
  1298. }
  1299.  
  1300. char *
  1301. xmalloc(size)
  1302.     int size;
  1303. {
  1304.     char *malloc();
  1305.  
  1306.     return malloc(size);
  1307. }
  1308.  
  1309. char *
  1310. xrealloc(region, size)
  1311.     char *region;
  1312.     int size;
  1313. {
  1314.     char *realloc();
  1315.  
  1316.     return realloc(region, size);
  1317. }
  1318.  
  1319. void
  1320. xfree(region)
  1321.     char *region;
  1322. {
  1323.     (void) free(region);
  1324. }
  1325. #endif    /* STANDALONE */
  1326.